C マクロ

提供:yonewiki

C++へ戻る


※このページではC言語にも存在していたという意味で記事タイトルがC マクロになっていますが、
C++でも同様です。C++だけの機能がある場合は明記します。

マクロ


マクロはC++言語においては、プリプロセッサの中での変数を使ったプログラム全体のテキスト文字列の一括置換処理を行う処理のための命令を意味していて、#define ディレクティブによってマクロ変数を定義できます。 簡単な使い方から複雑な使い方であるものまで種々のマクロが存在するため、最初の基礎の理解だけに留めていると、複雑なマクロ変数や変数の定義であるマクロ宣言に出くわしたとき、理解に苦しむことになります。こういう方法もあるので、VisualStudio利用者の人ならば、参考にしてみて下さい。


#undef はマクロ変数を解放する(変数の定義を消去する)ためのディレクティブです。こちらは比較的使い方が簡単です。

#define

まず、マクロの基本ですが、マクロ変数を定義するだけで、変数の中に入れる値を意識しない使い方は以下のとおりです。プログラム全体に関わる定数値処理や定型文法処理の切り替えが必要な時に活用することができます。サンプルでは一回だけの変換につかっているので実用的ではありませんが、変換の具体例を示すための強引なマクロ利用サンプルになっていることに留意して下さい。


#defeine マクロ変数名


のように#defineの後の半角空白での区切りの後にマクロ変数名を記述することで定義できます。


具体的に __MY_MACRO__ というマクロ変数を定義する場合は以下のとおりとなります。

#define __MY_MACRO__


マクロ変数には置き換えるべき値を代入することができて、プログラムソース中のマクロ変数をプログラムトークン処理に基づいて、一致する変数を代入された値に置き換えることができます。


例えば、__MY_MACRO__ を数値50に置き換える場合は

#define __MY_MACRO__ 50
int main(){
    int nMacroValue;
    nMacroValue = __MY_MACRO__ * 10;
}

というプログラムはプリプロセス処理によって

int main(){
    int nMacroValue;
    nMacroValue = 50 * 10;
}

に置き換えられ、nMacroValueの値は500になります。更に __MY_MACRO1__ に代入する値を 20 + 30 とした 同じ50でも __MY_MACRO2__ にカッコをつけて ( 20 + 30 ) にした場合とでは置き換え処理が異なるだけでなく、計算結果にも影響します。


具体的には以下の通りの違いになります。

#define __MY_MACRO__ 50
#define __MY_MACRO1__ 20 + 30
#define __MY_MACRO2__ ( 20 + 30 )
int main(){
    int nMacroValue;
    nMacroValue = __MY_MACRO__ * 10;
    nMacroValue1 = __MY_MACRO1__ * 10;
    nMacroValue2 = __MY_MACRO2__ * 10;
}

int main(){
    int nMacroValue;
    nMacroValue = 50 * 10;//500
    nMacroValue1 = 20 + 30 * 10;//積の計算が優先されるため 20 + 300 で 320
    nMacroValue2 = ( 20 + 30 ) * 10; // カッコが優先されて 50 * 100 で500
}

と上記のように変換されます。


さらに複雑なマクロとして引数リスト付きマクロ変数が定義できて、__MY_MACRO_ADD_(a,b) のようなマクロ変数を定義できて、パラメータを引数にしたマクロ置換の値をパラメータを使った値を記述できます。パラメータの数はメモリの許す限り、幾つでも定義できます。


文章で引数リスト付きマクロを説明しても具体的にはどういうものか想像できないので具体例をいかに示します。

#define __MY_MACRO_ADD_(a,b) ( a + b )

int main(){
    int nMacroValue;
    int nMacroValue1;
    int x = 20;
    int y = 30;
    nMacroValue = __MY_MACRO_ADD_(x, y) * 10;
    nMacroValue1 = __MY_MACRO_ADD_(90, 110) * 10;
}

という記述は変換されて

int main(){
    int nMacroValue;
    int x = 20;
    int y = 30;
    int nMacroValue;
    int nMacroValue1;
    nMacroValue = ( x + y ) * 10;// x = 20,y = 30,
                                 //( 20 + 30 ) *10 → 500 
    nMacroValue1 = ( 90 + 110 ) * 10;
}

と、こうなります。


さらに応用をきかせると引数は何回でも繰り返し使えるので、

#define __MY_MACRO_ADD_(a,b) ( a + b + a + b )

int main(){
    int nMacroValue;
    int x = 20;
    int y = 30;
    int nMacroValue;
    int nMacroValue1;
    nMacroValue = __MY_MACRO_ADD_(x, y) * 10;
    nMacroValue1 = __MY_MACRO_ADD_(90, 110) * 10;
}

という記述は変換されて

int main(){
    int nMacroValue;
    int x = 20;
    int y = 30;
    int nMacroValue;
    int nMacroValue1;
    nMacroValue = ( x + y + x + y ) * 10;//a = 20,b = 30,(20 + 30 + 20 + 30) * 10 → 1000
    nMacroValue1 = ( 90 + 110 + 90 + 110 ) * 10;// 4000
}

と、こうなります。

もっと応用をきかせるとやや機能的なマクロを定義することも出来ます。

#define __MY_MACRO_MAX__(a,b) ( (a) > (b) ? (a) : (b) )
#define __MY_MACRO_SWAP__(a,b) {int c; c = a; a = b; b = c;}
int main(){
    int nMacroValue;
    int x = 20;
    int y = 30;
    int nMacroValue;
    int nMacroValue1;
    int nMacroValue2;
    int nMacroValue3;
    nMacroValue = __MY_MACRO_MAX__(x, y) * 10;
    nMacroValue1 = __MY_MACRO_MAX__(90, 110) * 10;
    nMacroValue2 = __MY_MACRO_SWAP__(x, y) * 10;
    nMacroValue3 = __MY_MACRO_SWAP__(90, 110) * 10;
}

という記述は変換されて

int main(){
    int nMacroValue;
    int x = 20;
    int y = 30;
    int nMacroValue;
    int nMacroValue1;
    int nMacroValue2;
    int nMacroValue3;
    nMacroValue  = ( (x) > (y) ? (x) : (y) ) * 10;//x = 20, y = 30, 
                              //( (20) > (30) ? (20) : (30) ) * 10 → 300
    nMacroValue1 = ( (90) > (110) ? (90) : (110) ) * 10;//
                                                        //( (90) > (110) ? (90) : (110) ) * 10 → 1100
    nMacroValue2 = {int c; c = x; x = y; y = c;} * 10;//x = 20, y = 30
                                                      //{int c; c ← 20; x ← 30; y ← c(20);} * 10
                                                      // → {…} * 10 → 0(xとy)の値は入れ替わる。
    nMacroValue3 = {int c; c = 90; 90 = 110; 110 = c;} * 10;//{int c; c ← 90; 90 ← 110; 110 ← c(90);} * 10 → 0
                                                      //コンパイル エラー
}

といった具合に複雑な計算式を当て込むことで、最大値や値の入れ替えした値を返却するマクロとしての機能を持つ置換処理をプログラムソース全体にわたって処理してくれます。。ただしトークンの置き換えでMAXに一致すると処理が変わる可能性があるため、マクロ名が重複しないようにする必要があることと、引数付きの複雑なプログラムソースを組み込んだマクロ定義によって使い方を間違えるとエラーになるケースが生じることにも注意が必要になります。マクロの定義によっても、無意識のうちに構文エラーになるような使い方になってしまうような間違いも発生しやすいです。汎用性の高いマクロになっているか、よく確かめる必要があります。計算の優先度の入れ替わりや置き換え後の;や}の利用によって構文エラーになっていないか?意図した計算結果がいつでも得られるマクロになっているかを確実なものにする技術が必要です。


あまり、ややこしいマクロは組み込まない方が分かりやすいですが、使わざるを得ないプロジェクトがあれば、使ってプログラムのメンテナンス性を向上させることができます。自分ではあまりマクロを組み込まないという人でも、少なくとも他人が組んだマクロの展開結果が何を意図しているか読み解く力があれば、問題ないと思います。

#undef

#defineディレクティブで定義したマクロ変数を解放するためのディレクティブです。#undefディレクティブの後ろに半角スペースを挿入し、続けて解放したいマクロ変数名を記述し、以下のような形式で記述します。


#undef 解放するマクロ変数名


具体的には以下のように記述します。

#define __MY_MACRO__
#ifdef __MY_MACRO__
#define __MY_MACRO1(a,b)__ ( 5000 + (a) + (b))
#endif

#ifdef __MY_MACRO__
#undef __MY_MACRO1__
#undef __MY_MACRO__
#endif

上記のように引数付きマクロ変数でも、解放するときは引数の記述を省略できます。定義されていないマクロ変数を#undefディレクティブで解放する指示をしてもエラーにはなりません。もちろん、#ifdefディレクティブを使って、定義されているマクロ変数だけを解放するように組み込むこともできます。


C++へ戻る